@file:JvmName("AccessibilityScope")

package io.wongxd.accessibility

import android.os.Looper
import io.wongxd.solution.logger.WLogUtil
import kotlinx.coroutines.*
import java.io.Closeable
import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext

/** 保存 CoroutineScope **/
private var scopeRef: AtomicReference<SafeCoroutineScope?> = AtomicReference()

/** 自定义的 CoroutineScope **/
val accessibilityScope: CoroutineScope
    get() {
        while (true) {
            val existing = scopeRef.get()
            if (existing != null) {
                return existing
            }
            val newScope = SafeCoroutineScope(Dispatchers.Main)
            if (scopeRef.compareAndSet(null, newScope)) {
                return newScope
            }
        }
    }

/** 不会崩溃的 CoroutineScope **/
private class SafeCoroutineScope(context: CoroutineContext) : CoroutineScope, Closeable {
    override val coroutineContext: CoroutineContext =
        SupervisorJob() + context + UncaughtCoroutineExceptionHandler()

    override fun close() {
        coroutineContext.cancelChildren()
    }
}

/** 自定义 CoroutineExceptionHandler **/
private class UncaughtCoroutineExceptionHandler : CoroutineExceptionHandler,
    AbstractCoroutineContextElement(CoroutineExceptionHandler) {
    override fun handleException(context: CoroutineContext, exception: Throwable) {
        // 处理异常
        WLogUtil.errorTrace(exception)
    }
}

val isOnMainThread: Boolean
    get() = Looper.myLooper() == Looper.getMainLooper()

fun runOnMainThread(block: () -> Unit) {
    if (isOnMainThread) block.invoke()
    else accessibilityScope.launch(Dispatchers.Main) { block.invoke() }
}

suspend fun <T> switch2io(block: suspend () -> T): T {
    return withContext(Dispatchers.IO) {
        block.invoke()
    }
}

suspend fun <T> switch2ui(block: suspend () -> T): T {
    return withContext(Dispatchers.Main) {
        block.invoke()
    }
}